package com.pang.security.auth;

import com.pang.security.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @version 1.0
 * 功能目的描述 ：用于         ========>>>>>>>>>>>
 * @author： pang-yun
 * @date： 2021-06-11 09:05
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启方法级别安全配置功能！
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;


    //登录成功的处理器
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    //登录失败的处理器
    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    //匿名用户无权限访问时异常
    @Autowired
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;

    //权限不足处理器
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    //注销操作处理器
    @Autowired
    private MyLogoutHandler myLogoutHandler;
    //注销成功处理器
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    //超时处理器
    @Autowired
    private MyInvalidSessionStrategy myInvalidSessionStrategy;

    //被挤下线时的处理方式
    @Autowired
    private MyExpiredSessionStrategy myExpiredSessionStrategy;

    /**
     * 通过auth可以在内存中构建虚拟的用户名和密码
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      /*  auth.inMemoryAuthentication()
                .withUser("user")   //内存中用户姓名
                .password(passwordEncoder.encode("123"))
                .roles("user")            //角色
                .and()
                .withUser("admin")
                .password(passwordEncoder.encode("123"))
                .roles("admin")
                .and()
                .passwordEncoder(passwordEncoder); //配置加密方式  配置之后passwordEncoder.encode("123")写
                这种方法将 用户名和密码写死在内存中*/

        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);


    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      /*  //开启httpBasic 认证
        http.httpBasic()
                //and  表示连接符  可以算是链式编程  其实是返回http
                .and()
                //认证所有请求
                .authorizeRequests()
                //所有请求都必须认证成功
                .anyRequest()
                .authenticated();*/

        //表单
        //任何请求都会被认证，所有请求都会被拦截，包括登录。html     那么登录页面也无法进入
        http.authorizeRequests()
                //将login login.html放行
                .antMatchers("/login", "/login.html").permitAll()
             /*   //hasAnyAuthority  hasRole  这里是什么资源  需要什么角色、权限
                .antMatchers("/users", "/roles")
                .hasAnyAuthority("ROLE_user", "ROLE_admin")
                .antMatchers("/menus", "/others")
                .hasRole("admin")*/
                .anyRequest().authenticated()
                .and()
                //允许注销操作
                .logout().permitAll()
                //添加注销操作处理器
                .addLogoutHandler(myLogoutHandler)
                //注销成功的处理方案
                .logoutSuccessHandler(myLogoutSuccessHandler)
                //登出之后删除cookie
                .deleteCookies("JSESSIONID")
                .and()
                //设置登录页   会自动跳转到此页面
                .formLogin().loginPage("/login.html")
                //设置form表单的登录控制器，默认是login 设置表单的action  处理认证请求的路径
                .loginProcessingUrl("/login")
                //登录表单form用户名输入框input的name名， 不修改的话默认是username
                .usernameParameter("username")
                //登录表单form用户名输入框input的password名， 不修改的话默认是password
                .passwordParameter("password")
                //登录成功之后，默认的转跳路径
                //.successForwardUrl("/home").permitAll()
                //登录成功后的自定义处理器  此时我们不需要 跳转页面
                .successHandler(myAuthenticationSuccessHandler)
                //登录失败url
                //.failureUrl("/login/error");
                .failureHandler(myAuthenticationFailureHandler)
                .and()
                .exceptionHandling()
                //未登录访问资源时提示的异常
                .authenticationEntryPoint(myAuthenticationEntryPoint)
                //权限不足时提示的异常
                .accessDeniedHandler(myAccessDeniedHandler)
                //会话创建方式
                .and()
                //会话创建方式
                //.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);

                //会话超时处理
                .sessionManagement().invalidSessionStrategy(myInvalidSessionStrategy)
                //限制用户数量，最大允许登录数量
                .maximumSessions(1)
                //是否允许另一个账户登录
                .maxSessionsPreventsLogin(false)
                  .expiredSessionStrategy(myExpiredSessionStrategy);




        //关闭跨域攻击
        http.csrf().disable();
    }
}
